#include "../src/lexer/lexercc.hpp"
#include "../src/parser/parsercc.hpp"
#include <filesystem>
#include <iomanip>
#include <iostream>
#include <sstream>

using std::cin;
using std::cout;
using std::fstream;
using std::ifstream;
namespace fs = std::filesystem;

/**
 * 这是一个完整的例子，从../testcase/里读取词法和文法文件，将生成的程序输出到
 * ../generated/文件夹中，并且会读取../testcase/tiny.txt进行语法分析，将结果
 * 输出到../output/文件夹中
 */ 
int main() {
    cout << "\n\n";
    ifstream lexIn;
    ifstream grammarIn;
    ifstream astConfigIn;
    ifstream sourceIn;
    fstream grammarOut;
    fstream parseOut;
    fstream astJsonOut;
    fstream astTxtOut;
    if(!fs::exists("../output")){
        fs::create_directory("../output");
    }
    const string TEST_BASE = "../testcase/tiny/";
    const string OUT_BASE = "../output/tiny/";
    __OPEN_AND_CHECK(lexIn, TEST_BASE + "tiny_lex.json", false);
    __OPEN_AND_CHECK(grammarIn, TEST_BASE + "tiny_syntax.txt", false);
    __OPEN_AND_CHECK(astConfigIn, TEST_BASE + "tiny_ast_conf.json", false);
    __OPEN_AND_CHECK(sourceIn, TEST_BASE + "tiny.txt", false);
    __OPEN_AND_CHECK(grammarOut, OUT_BASE + "tiny_table.csv", true);
    __OPEN_AND_CHECK(parseOut, OUT_BASE + "tiny_parse_tree.txt", true);
    __OPEN_AND_CHECK(astJsonOut, OUT_BASE + "tiny_AST.json", true);
    __OPEN_AND_CHECK(astTxtOut, OUT_BASE + "tiny_AST.txt", true);
    // ---------------------------------------------------------------------- //
    // Lex 
    MyLexer lexer = buildLexerFromJson(lexIn);
    auto tokens = lexer.lex(sourceIn);
    // Parse
    MyParser parser;
    clock_t st = clock();
    parser.buildParserFromSyntaxDef(grammarIn);
    parser.printParseTable(grammarOut);
    cout << "++++ Parse table saved at ./output/tiny_table.csv\n";
    MyParser::PtrParseTreeNode parseTree;
    parseTree = parser.parse(tokens);
    // Print parse tree
    parser.printParseTree(parseOut, parseTree);
    cout << "++++ Parse tree saved at ./output/tiny_parse_tree.txt\n";
    // Print AST
    ASTConfig config = ASTConfig::configWithJson(astConfigIn);
    PtrASTNode ast;
    ast = ASTNode::buildAST(parseTree, config);
    ast->printAST(astTxtOut);
    astJsonOut << std::setw(2) << my_json_wrap(ast) << endl;
    cout << "++++ AST saved at ./output/tiny_AST.txt\n";
    // Generate codes
    writeLexer(lexer, "../generated/", "../src/lexer", false);
    writeParser(parser, "../generated/", "../src/parser", true);
    // ---------------------------------------------------------------------- //
    lexIn.close();
    grammarIn.close();
    astConfigIn.close();
    sourceIn.close();
    grammarOut.close();
    parseOut.close();
    astJsonOut.close();
    astTxtOut.close();
    system("pause");
}
